package com.example.voltorb.flip;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.os.Vibrator;

public class Game {

	private final static int MAX_COINS[] = {20, 50, 100, 200, 500, 1000};
	
	final int gridRows, gridColumns, gridSize;
	
	enum GameState { PLAYING, MARKING, WON, LOST };
	
	private Context c;
	
	private int level;
	private int currentCoins;
	private boolean isMarkModeOn;

	private GameState state;
	private List<Tile> tiles;

	public Game(Context context, int rows, int columns) {
		this.c = context;
		
		this.gridRows = rows;
		this.gridColumns = columns;
		this.gridSize = this.gridRows * this.gridColumns;

		this.level = 1;
		
        this.tiles = new ArrayList<Tile>();
		
		this.initNewBoard();
	}
	
	public void initNewBoard() {
		this.currentCoins = 0;
		this.isMarkModeOn = false;
		if (this.getState() == GameState.WON)
			this.level++;
        // Randomize the board content
		int totalCoins = 0;
		tiles.clear();
        for (int i = 0; i < gridSize; i++) {
        	int randValue = (int) Math.floor(Math.random() * 4);
        	
        	Tile curTile;
        	if (randValue > 0) {
        		// Check current total value
        		if (this.level < MAX_COINS.length)
	        		while (totalCoins * randValue > MAX_COINS[this.level])
	        			randValue--;
        		// Add current value to total
        		if (totalCoins == 0)
        			totalCoins = randValue;
        		else
        			totalCoins *= randValue;
        		// Create new coin tile
        		curTile = new CoinTile(randValue);
        	}
        	else
        		curTile = new VoltorbTile();
        	tiles.add(curTile);
        }
        
        // Add the row summary tiles
        for (int i = 0; i < gridRows; i++) {
        	int amountOfCoins = 0;
        	int amountOfVoltorbs = 0;
        	
        	int breakPoint = i * (gridColumns + 1);
        	int j;
        	for (j = breakPoint; j < breakPoint + gridColumns; j++) {
        		Tile curTile = tiles.get(j);
        		if (tiles.get(j) instanceof CoinTile)
        			amountOfCoins += ((CoinTile) curTile).getCoinAmount();
        		else
        			amountOfVoltorbs++;
        	}
        	
        	tiles.add(j, new SummaryTile(amountOfCoins, amountOfVoltorbs));
        }
        
        // Add the column summary tiles
        for (int i = 0; i < gridColumns; i++) {
        	int amountOfCoins = 0;
        	int amountOfVoltorbs = 0;
        	
        	for (int j = i; j < gridSize + i; j += gridColumns + 1) {
        		Tile curTile = tiles.get(j);
        		if (tiles.get(j) instanceof CoinTile)
        			amountOfCoins += ((CoinTile) curTile).getCoinAmount();
        		else
        			amountOfVoltorbs++;
        	}
        	
        	tiles.add(new SummaryTile(amountOfCoins, amountOfVoltorbs));
        }
        
        // Set state to playing
        this.setState(GameState.PLAYING);
	}
	
	private void setState(GameState newState) {
		this.state = newState;
		switch (this.state) {
		case PLAYING:
		case MARKING:
			break;
		case WON:
			MainActivity main = (MainActivity) this.c;
			main.addCollectedCoins();
			main.showEndingDialog();
			break;
		case LOST:
			// Get instance of Vibrator from current Context
    		Vibrator vibe = (Vibrator) this.c.getSystemService(Context.VIBRATOR_SERVICE);
    		// Vibrate for one second
    		vibe.vibrate(1000);
    		
    		((MainActivity) this.c).showEndingDialog();
			break;
		}
	}
	
	public GameState getState() {
		return this.state;
	}

	public List<Tile> getTiles() {
		return this.tiles;
	}
	
	public void turnTile(int position) {
		Tile t = tiles.get(position);
		
		t.turn();
		if (t instanceof VoltorbTile) {
			setState(GameState.LOST);
		} else if (t instanceof CoinTile) {
			this.addCurrentCoins(((CoinTile) t).getCoinAmount());
			((MainActivity) this.c).updateCurrentCoins();
		}
		
		// Check for game ending
		if (this.isCleared()) {
			this.setState(GameState.WON);
		}
	}
	
	private int addCurrentCoins(int amount) {
		if (this.currentCoins == 0)
			this.currentCoins = amount;
		else
			this.currentCoins *= amount;
		return this.currentCoins;
	}
	
	public boolean isCleared() {
		for (Tile t : this.tiles) {
			if (t instanceof CoinTile && !t.isTurned() && ((CoinTile) t).getCoinAmount() > 1) {
				return false;
			}
		}
		return true;
	}

	public int getLevel() {
		return this.level;
	}

	public int getCollectedCoins() {
		return this.currentCoins;
	}
	
	public boolean toggleMarkMode() {
		if (state == GameState.PLAYING)
			state = GameState.MARKING;
		else
			state = GameState.PLAYING;
		return isMarkModeOn;
	}
	
	public boolean isMarkModeOn() {
		return state == GameState.MARKING;
	}

	public void showBoard() {
		for (Tile t : getTiles()) {
			if (!t.isTurned())
				t.turn();
		}
	}
}
